package com.jzo2o.health.handler;

import cn.hutool.core.util.ObjectUtil;
import com.jzo2o.api.trade.RefundRecordApi;
import com.jzo2o.api.trade.dto.response.ExecutionResultResDTO;
import com.jzo2o.api.trade.enums.RefundStatusEnum;
import com.jzo2o.common.expcetions.BadRequestException;
import com.jzo2o.common.expcetions.DBException;
import com.jzo2o.common.model.CurrentUserInfo;
import com.jzo2o.common.utils.ObjectUtils;
import com.jzo2o.health.enums.OrderPayStatusEnum;
import com.jzo2o.health.enums.OrderStatusEnum;
import com.jzo2o.health.job.OrderJob;
import com.jzo2o.health.mapper.OrdersCancelledMapper;
import com.jzo2o.health.mapper.OrdersMapper;
import com.jzo2o.health.model.domain.Orders;
import com.jzo2o.health.model.domain.OrdersCancelled;
import com.jzo2o.health.model.domain.OrdersRefund;
import com.jzo2o.health.model.domain.ReservationSetting;
import com.jzo2o.health.properties.OrdersJobProperties;
import com.jzo2o.health.service.IOrdersCancelledService;
import com.jzo2o.health.service.IOrdersRefundService;
import com.jzo2o.health.service.IOrdersService;
import com.jzo2o.health.service.IReservationSettingService;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import net.bytebuddy.asm.Advice;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 订单相关定时任务
 *
 * @author itcast
 * @create 2023/9/2 16:44
 **/
@Slf4j
@Component
public class OrdersHandler {

    @Resource
    private RefundRecordApi refundRecordApi;
    //解决同级方法调用，事务失效问题
    @Resource
    private OrdersHandler owner;
    @Resource
    private OrdersJobProperties ordersJobProperties;

    @Resource
    private IOrdersService ordersService;

    @Resource
    private OrdersCancelledMapper ordersCancelledMapper;

    @Resource
    private IReservationSettingService reservationSettingService;

    @Autowired
    private ApplicationContext applicationContext;


    /**
     * 支付超时取消订单
     * 每分钟执行一次
     */
    @XxlJob(value = "cancelOverTimePayOrder")
    public void cancelOverTimePayOrder() {

        //select * from orders where order_status = 0 and order_pay_status = 0 and
        LocalDateTime fifteenMinutesAgo = LocalDateTime.now().minusMinutes(2);

        List<Orders> ordersList = ordersService.lambdaQuery()
                .eq(Orders::getOrderStatus, OrderStatusEnum.NO_PAY.getStatus())
                .eq(Orders::getPayStatus, OrderPayStatusEnum.NO_PAY.getStatus())
                .lt(Orders::getCreateTime, fifteenMinutesAgo)
                .list();

        if(ObjectUtil.isEmpty(ordersList)){
            return;
        }

        for (Orders orders : ordersList) {

            ordersService.lambdaUpdate()
                    .eq(Orders::getId, orders.getId())
                    .set(Orders::getOrderStatus, OrderStatusEnum.CANCELLED.getStatus())
                    .update();

            // 插入取消订单表
            OrdersCancelled ordersCancelled = new OrdersCancelled();

//            ordersCancelled.setCancellerId();
            ordersCancelled.setId(orders.getId());
            ordersCancelled.setCancellerType(4);
            ordersCancelled.setCancelReason("超时自动取消");
            ordersCancelled.setCancelTime(LocalDateTime.now());

            ordersCancelledMapper.insert(ordersCancelled);

            // 预约表人数+1
            reservationSettingService.lambdaUpdate()
                    .eq(ReservationSetting::getOrderDate, orders.getReservationDate())
                    .setSql("reservations = reservations - 1")
                    .update();
        }

    }

    /**
     * 订单退款异步任务
     */
//    @XxlJob(value = "handleRefundOrders")
//    public void handleRefundOrders() {
//
//    }

    /**
     * 订单退款处理
     *
     * @param id                    订单id
     * @param executionResultResDTO 第三方退款信息
     */
//    @Transactional(rollbackFor = Exception.class)
//    public void refundOrder(Long id, ExecutionResultResDTO executionResultResDTO) {
//        //1.调用支付服务的Feign接口进行退款申请
//        try {
//            executionResultResDTO = refundRecordApi.refundTrading(id, BigDecimal.valueOf(0.01));
//        } catch (Exception e) {
//            log.error("[订单退款处理]退款申请接口调用失败，退款信息:{}，异常信息",id, e);
//            throw new BadRequestException("[订单退款处理]退款申请接口调用失败");
//        }
//
//        //2.从响应结果中获取退款处理状态
//        Integer refundStatus = executionResultResDTO.getRefundStatus();
//
//        //3.如果是退款中，则再查询一次退款结果
//        if(ObjectUtils.equals(refundStatus, OrderPayStatusEnum.REFUNDING.getStatus())) {
//            try {
//                TimeUnit.SECONDS.sleep(2);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
//
//            //再发起一次退款请求，就是查询退款结果了
//            executionResultResDTO = refundRecordApi.refundTrading(id, BigDecimal.valueOf(0.01));
//            refundStatus = executionResultResDTO.getRefundStatus();
//        }
//
//        //4.更新订单表退款字段信息（退款状态、支付服务退款订单号、第三方退款订单号）
//        boolean resultOrder = ordersService.lambdaUpdate()
//                .eq(Orders::getId, id) //更新条件
//                .ne(Orders::getPayStatus, refundStatus)//更新条件
//                .set(Orders::getPayStatus, refundStatus) //退款状态
//                .set(Orders::getRefundNo, executionResultResDTO.getRefundNo()) //支付服务退款订单号
//                .set(Orders::getRefundId, executionResultResDTO.getRefundId()) //第三方退款订单号
//                .update();
//        if(!resultOrder){
//            log.error("[订单退款处理]订单表退款状态更新失败，退款信息：{}", id);
//            return;
//        }
//
//        //5.删除退款记录
////        boolean resultRefund = ordersCancelledService.removeById(ordersRefund.getId());
////        if(!resultRefund){
////            log.error("[订单退款处理]删除退款记录失败，退款信息：{}", ordersRefund);
////        }
//
//        log.info("[订单退款处理]退款处理成功，退款信息：{}，退款状态：{}", id, refundStatus);
//    }
//
//    @Autowired
//    private IOrdersRefundService ordersRefundService;
//
//    @Resource
//    private IOrdersCancelledService ordersCancelledService;
//
//    /**
//     * 取消派单中订单
//     *
//     * @param orders
//     * @param cancelReason
//     */
//    @Async("taskExecutor")
//    @Transactional(rollbackFor = Exception.class)
//    public void cancelRefundOrder(Orders orders, String cancelReason, CurrentUserInfo userInfo) {
//        //1. 添加取消记录
//        OrdersCancelled ordersCanceled = new OrdersCancelled();
//        ordersCanceled.setId(orders.getId());//订单id
//        ordersCanceled.setCancellerId(userInfo.getId()); //取消人id
//        ordersCanceled.setCancellerType(userInfo.getUserType());//取消人类型
//        ordersCanceled.setCancellerName(userInfo.getName());//取消人姓名
//        ordersCanceled.setCancelReason(cancelReason);//取消原因
//        ordersCanceled.setCancelTime(LocalDateTime.now());//取消时间
//        boolean resultCancel = ordersCancelledService.save(ordersCanceled);
//        if(!resultCancel) {
//            throw new DBException("添加取消记录失败");
//        }
//
//        //2. 更新订单状态 update orders set order_status=?,refund_status=? where id=?
//        boolean resultOrder = ordersService.lambdaUpdate()
//                .eq(Orders::getId, orders.getId())
//                .set(Orders::getOrderStatus, OrderStatusEnum.CLOSED.getStatus()) //已关闭
//                .set(Orders::getPayStatus, RefundStatusEnum.SENDING.getCode()) //退款中
//                .update();
//        if(!resultOrder) {
//            throw new DBException("更新订单失败");
//        }
//
//        //3. 添加退款记录
//        OrdersRefund ordersRefund = new OrdersRefund();
//        ordersRefund.setId(orders.getId());
//        ordersRefund.setTradingOrderNo(orders.getTradingOrderNo());
//        //ordersRefund.setRealPayAmount(orders.getRealPayAmount());
//        ordersRefund.setRealPayAmount(BigDecimal.valueOf(0.01));//由于前面测试支付都是0.01，这里为方便演示也只能写0.01。 不要使用new BigDecimal(double)，这种会精度丢失
//        boolean resultRefund = ordersRefundService.save(ordersRefund);
//        if(!resultRefund) {
//            throw new DBException("添加退款记录失败");
//        }
//
//        OrdersHandler owner = applicationContext.getBean(OrdersHandler.class);
//        //4. 申请退款
//        owner.refundOrder(ordersRefund);
//    }
}
